﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PSE.Framework.ProviderLoader.Configuration;
using PSE.Framework.ProviderLoader;
using PSE.ProcessManager.Entity;
using System.IO;
using System.Configuration;
using System.ComponentModel;
using PSE.ProcessManager.Entity.Enums;

namespace PSE.ProcessManager.ResourceAccess.FileSystemProvider
{
    public class ProcessManagerResourceAccess : BaseProvider, IProcessManagerResourceAccess
    {
        private const string inteligenceModuleFilePathConfigKey = "inteligenceModuleFilePath";
        private const string processFilePathConfigKey = "processFilePath";
        private const string messageFilePathConfigKey = "messageFilePath";
        private const string logFilePathConfigKey = "logFilePath";

        private InteligenceModuleResourceAccess _inteligenceModuleRA;
        private ProcessResourceAccess _processRA;
        private MessageResourceAccess _messageRA;
        private LogResourceAccess _logRA;

        public InteligenceModuleResourceAccess InteligenceModuleRA
        {
            get
            {
                return _inteligenceModuleRA;
            }
        }

        public ProcessResourceAccess ProcessRA
        {
            get
            {
                return _processRA;
            }
        }

        public MessageResourceAccess MessageRA
        {
            get
            {
                return _messageRA;
            }
        }


        public ProcessManagerResourceAccess(ProviderConfigurationElement configuration)
            : base(configuration)
        {
            ValidateConfiguration(configuration);

            string inteligenceModuleFilePath = configuration.Settings[inteligenceModuleFilePathConfigKey].Value;
            _inteligenceModuleRA = new InteligenceModuleResourceAccess(inteligenceModuleFilePath);

            string processFilePath = configuration.Settings[processFilePathConfigKey].Value;
            _processRA = new ProcessResourceAccess(processFilePath);

            string messageFilePath = configuration.Settings[messageFilePathConfigKey].Value;
            _messageRA = new MessageResourceAccess(messageFilePath);

            string logFilePath = configuration.Settings[logFilePathConfigKey].Value;
            _logRA = new LogResourceAccess(logFilePath);
        }

        /// <summary>
        /// Realizar a validação dos parâmetros de configuração
        /// </summary>
        /// <param name="configuration"></param>
        private void ValidateConfiguration(ProviderConfigurationElement configuration)
        {
            ValidateInformedKey(configuration, inteligenceModuleFilePathConfigKey);
            ValidateInformedKey(configuration, processFilePathConfigKey);
            ValidateInformedKey(configuration, messageFilePathConfigKey);
            ValidateInformedKey(configuration, logFilePathConfigKey);
        }

        /// <summary>
        /// Validar se o arquivo foi informado
        /// </summary>
        /// <param name="configuration"></param>
        /// <param name="filePathKey"></param>
        private void ValidateInformedKey(ProviderConfigurationElement configuration, string key)
        {
            //se nm foi informa a configuracao do caminho do arquivo de intenligence modules
            if (!configuration.Settings.AllKeys.Contains<string>(key) || string.IsNullOrEmpty(configuration.Settings[key].Value))
            {
                throw new ConfigurationErrorsException(string.Format("The config key '{0}' must be informed in the 'Process Manager Resource Access Provider' configuration.", key));
            }
        }

        #region Métodos utilizados pelo Configurador

        public List<ProcessEntity> RetrieveProcessList()
        {
            return _processRA.GetAll();
        }

        public List<InteligenceModuleEntity> RetrieveInteligenceModules()
        {
            return _inteligenceModuleRA.GetAll();
        }

        public List<MessageEntity> RetrieveMessageList(int? processId)
        {
            List<MessageEntity> ret = new List<MessageEntity>();
            List<MessageEntity> allMessages = _messageRA.GetAll();
            List<MessageEntity> messagesFromProcess;

            if (processId.HasValue)
                messagesFromProcess = allMessages.FindAll(m => m.ProcessId == processId.Value);
            else
                messagesFromProcess = allMessages;


            foreach (MessageEntity entity in messagesFromProcess)
            {
                ret.Add(entity);
            }

            return ret;
        }

        /// <summary>
        /// Salvar um processo
        /// </summary>
        /// <param name="process"></param>
        public void SaveProcess(ProcessEntity process)
        {
            if (process.Id.HasValue)
                _processRA.Update(process);
            else
                _processRA.Insert(process);

            //salvar as mensagens de uma processo
            SaveMessages(process.Id.GetValueOrDefault(), process.Messages);
        }

        /// <summary>
        /// Salvar as mensagens de uma processo
        /// </summary>
        /// <param name="messages"></param>
        private void SaveMessages(int processId, List<MessageEntity> messages)
        {
            List<MessageEntity> messagesToInsert = new List<MessageEntity>();
            List<MessageEntity> messagesToUpdate = new List<MessageEntity>();

            foreach (MessageEntity message in messages)
            {
                if (message.Id.HasValue)
                {
                    message.ProcessId = processId;
                    messagesToUpdate.Add(message);
                }
                else
                {
                    message.ProcessId = processId;
                    messagesToInsert.Add(message);
                }
            }

            _messageRA.Insert(messagesToInsert);
            _messageRA.Update(messagesToUpdate);
        }

        public void DeleteMessage(int messageId)
        {
            _messageRA.Delete(messageId);
        }

        //public void ExportConfigFile(List<ProcessEntity> listProcess, List<InteligenceModuleEntity> listInteligenceModule)
        //{
        //    List<MessageEntity> listMessage = new List<MessageEntity>();

        //    foreach (ProcessEntity process in listProcess)
        //    {
        //        if (process.Id != null)
        //        {
        //            if (process.Messages != null)
        //            {
        //                foreach (MessageEntity message in process.Messages)
        //                {
        //                    listMessage.Add(message);
        //                }
        //            }
        //        }
        //    }

        //    _inteligenceModuleRA.ExportConfigFile(listInteligenceModule);
        //    _messageRA.ExportConfigFile(listMessage);
        //    _processRA.ExportConfigFile(listProcess);
        //}

        #endregion

        #region Métodos utilizados pelo Server
        public List<int> RetrieveAutoStartProcesses()
        {
            List<int> ret = new List<int>();
            List<ProcessEntity> processes = _processRA.GetAll();
            if (processes.Count > 0)
            {
                List<ProcessEntity> selectResult = processes.FindAll(p => p.InitializationType == StartUpType.Automatic);

                foreach (ProcessEntity process in selectResult)
                {
                    ret.Add(process.Id.GetValueOrDefault());
                }
            }

            return ret;
        }

        public ProcessEntity RetrieveProcessConfiguration(int processId)
        {
            return _processRA.GetOne(processId);
        }

        public void RetrieveInteligenceModuleAndProcessConfiguration(int processId, out ProcessEntity processConfiguration, out InteligenceModuleEntity inteligenceModuleConfiguration)
        {
            processConfiguration = _processRA.GetOne(processId);

            if (processConfiguration != null)
            {
                inteligenceModuleConfiguration = _inteligenceModuleRA.GetOne(processConfiguration.InteligenceModuleId);

                if (inteligenceModuleConfiguration == null)
                {
                    throw new Exception(string.Format("InteligenceModule '{0}' not found.", processConfiguration.InteligenceModuleId));
                }
            }
            else
            {
                throw new Exception(string.Format("Process '{0}' not found.", processId));
            }
        }

        #endregion

        #region Metodos do Log

        public List<LogEntity> RetrieveLogList(int processId)
        {
            return _logRA.GetAll(processId);
        }

        public LogEntity RetrieveLastProcessLog(int processId)
        {
            return _logRA.GetLast(processId);
        }

        public int SaveLog(int processId, string userName, DateTime startDate)
        {
            return _logRA.Insert(new LogEntity() { ProcessID = processId, UserName = userName, StartDate = startDate });
        }

        public void SaveLog(int idLog, DateTime endDate)
        {
            _logRA.Update(idLog, endDate);
        }

        public void SaveLog(int idLog, DateTime endDate, string errorMessage)
        {
            _logRA.Update(idLog, endDate, errorMessage);
        }

        #endregion


    }
}
